package cc.shacocloud.kotlin.tools.http

import cc.shacocloud.kotlin.tools.http.Http.APPLICATION_JSON
import com.fasterxml.jackson.core.type.TypeReference
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Response
import cc.shacocloud.kotlin.tools.json.Json as Json2

/**
 * 响应对象解析为 json
 * @author 思追(shaco)
 */
fun <T> Response.toJson(
    deserializer: DeserializationStrategy<T>,
    checkSuccess: Boolean = true,
): T {
    if (checkSuccess) assertSuccess()
    assertContentTypeJson()

    if (body == null) {
        throw RuntimeException("响应体为空，无法解析！")
    }

    return Json.decodeFromString(deserializer, body!!.string())
}


/**
 * 响应对象解析为 json
 * @author 思追(shaco)
 */
inline fun <reified T> Response.toJson(
    checkSuccess: Boolean = true,
): T {
    if (checkSuccess) assertSuccess()
    assertContentTypeJson()

    if (body == null) {
        throw RuntimeException("响应体为空，无法解析！")
    }

    return Json.decodeFromString<T>(body!!.string())
}

/**
 * 响应对象解析为 json
 * @author 思追(shaco)
 */
inline fun <reified T> Response.toJson(
    clazz: Class<T>,
    checkSuccess: Boolean = true,
): T {
    if (checkSuccess) assertSuccess()
    assertContentTypeJson()

    if (body == null) {
        throw RuntimeException("响应体为空，无法解析！")
    }

    return Json2.decodeValue(body!!.string(), clazz)
}


/**
 * 响应对象解析为 json
 * @author 思追(shaco)
 */
fun <T> Response.toJson(
    type: TypeReference<T>,
    checkSuccess: Boolean = true,
): T {
    if (checkSuccess) assertSuccess()
    assertContentTypeJson()

    if (body == null) {
        throw RuntimeException("响应体为空，无法解析！")
    }

    return Json2.decodeValue(body!!.string(), type)
}

/**
 * 断言内容类型是 json
 *
 * @author 思追(shaco)
 */
fun Response.assertContentTypeJson() {
    val contentType = headers["Content-Type"]?.toMediaTypeOrNull()
        ?: throw RuntimeException("未知的 Content-Type 值：${headers["Content-Type"]}")

    if (APPLICATION_JSON.type != contentType.type || APPLICATION_JSON.subtype != contentType.subtype) {
        throw RuntimeException("Content-Type 值[${contentType}] 无法使用 json 格式解析器")
    }
}

/**
 * 断言当前请求是成功的
 */
fun Response.assertSuccess() {
    if (!isSuccessful) {
        throw RuntimeException("失败的响应，状态码：${code}，状态消息：${message}")
    }
}
